//*********************************************
//  This is Geant4 Template
//                                  author:Qian
//

#include "Verbose.hh"

#include "G4SystemOfUnits.hh"
#include "G4Box.hh"
#include "G4VPhysicalVolume.hh"
#include "G4LogicalVolumeStore.hh"
#include "G4PhysicalVolumeStore.hh"

#include "MyDetectorConstruction.hh"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#include "TObject.h"
#include "TFile.h"
#include "TTree.h"
#include "TSystem.h"
#include "TNtuple.h"
#include "TH1.h"
#include "TH2.h"
#include "TVector3.h"

#pragma GCC diagnostic pop

#include "MyOpticalPhotonAnalysis.hh"

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

MyOpticalPhotonAnalysis::MyOpticalPhotonAnalysis()
{
    SetFileName("output.root");
    fTotalEventNumber = 0;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

MyOpticalPhotonAnalysis::~MyOpticalPhotonAnalysis()
{
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyOpticalPhotonAnalysis::BeginOfRunAction()
{
    if (!active)
        return;

    if (verbose)
        G4cout << "====>MyOpticalPhotonAnalysis::BeginOfRunAction()" << G4endl;

    fRootFp = new TFile(fFileName, "recreate");
    if (!fRootFp)
    {
        G4cout << "\n====>MyOpticalPhotonAnalysis::BeginOfRunAction(): "
               << "cannot open " << fFileName << G4endl;
        return;
    }

    fPGGeneratorList = PGGeneratorList::GetInstance();
    fPGGenerator = fPGGeneratorList->GetGenerator();

    fTree = new TTree("SimuInfo", "Tree of data events");
    fTree->Branch("PGTypeFlag",        &fPGTypeFlag,       "PGTypeFlag/I");
    fTree->Branch("TruthEnergy",       &fTruthEnergy,      "TruthEnergy/D");
    fTree->Branch("TruthPos",          &fTruthPos,         "TruthPos[3]/D");
    fTree->Branch("TruthMomDir",       &fTruthMomDir,      "TruthMomDir[3]/D");

    fTree->Branch("NumOfOpPhoton",     &fNumOfOpPhoton,    "NumOfOpPhoton/I");
    fTree->Branch("PhotonEnergy",      &fPhotonEnergy,     "PhotonEnergy[NumOfOpPhoton]/D");
    fTree->Branch("PhotonCatchTime",   &fPhotonCatchTime,  "PhotonCatchTime[NumOfOpPhoton]/D");
    fTree->Branch("PhotonPos",         &fPhotonPos,        "PhotonPos[NumOfOpPhoton][3]/D");
    fTree->Branch("PhotonMomDir",      &fPhotonMomDir,     "PhotonMomDir[NumOfOpPhoton][3]/D");

    //------- add your codes down here
    //
    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyOpticalPhotonAnalysis::EndOfRunAction()
{
    if (!active)
        return;

    if (verbose)
        G4cout << "====>MyOpticalPhotonAnalysis::EndOfRunAction()" << G4endl;

    if (!fRootFp)
    {
        G4cout << "\n====>MyOpticalPhotonAnalysis::EndOfRunAction(): "
               << "cannot open " << fFileName << G4endl;
        return;
    }

    //------- add your codes down here
    //

    PGPSConfig ConfigPS = fPGGeneratorList->GetPGPSConfig();
    // fGitVersion = TString(VERSION_GIT_HEAD_VERSION);

    G4cout << "\n====>In total " << fTree->GetEntries() << " Events have been stored." << G4endl;
    fRootFp->cd();
    fTree->AutoSave();
    // fRootFp->Write();
    fRootFp->Close();
    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyOpticalPhotonAnalysis::BeginOfEventAction(const G4Event *)
{
    if (!active)
        return;

    if (verbose > 1)
        G4cout << "====>MyOpticalPhotonAnalysis::BeginOfEventAction()" << G4endl;

    fPGTypeFlag = 0;
    fTruthEnergy = 0.;
    for(Int_t i = 0; i < 3; ++i)
    {
        fTruthPos[i] = 0.;
        fTruthMomDir[i] = 0.;
    }
    fNumOfOpPhoton = 0;
    for(Int_t i = 0; i < MAXOPPHOTON; ++i)
    {
        fPhotonEnergy[i] = 0.;
        fPhotonCatchTime[i] = 0.;
        for (Int_t j = 0; j < 3; ++j)
        {
            fPhotonPos[i][j] = 0.;
            fPhotonMomDir[i][j] = 0.;
        }
    }


    //------- add your codes down here
    //
    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

void MyOpticalPhotonAnalysis::EndOfEventAction(const G4Event *)
{
    if (!active)
        return;

    if (verbose > 1)
        G4cout << "====>MyOpticalPhotonAnalysis::EndOfEventAction()" << G4endl;

    //------- add your codes down here
    //
    ++fTotalEventNumber;
    if (fTotalEventNumber % 1000 == 0)
        G4cout << "\n---> Generate " << fTotalEventNumber << " events." << G4endl;

    fPGTypeFlag = fPGGenerator->GetTypeFlag();
    fTruthEnergy = fPGGenerator->GetParticleEnergy();
    G4ThreeVector TruthPos = fPGGenerator->GetParticlePosition();
    G4ThreeVector TruthMomDir = fPGGenerator->GetParticleMomentumDirection();

    for(Int_t i = 0; i < 3; ++i)
    {
        fTruthPos[i] = TruthPos[i];
        fTruthMomDir[i] = TruthMomDir[i];
    }

    fTree->Fill();

    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
G4ClassificationOfNewTrack MyOpticalPhotonAnalysis::ClassifyNewTrack(const G4Track *)
{
    if (!active)
        return fUrgent;

    //------- add your codes down here
    //
    return fUrgent;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyOpticalPhotonAnalysis::PreTrackingAction(const G4Track *)
{
    if (!active)
        return;

    //------- add your codes down here
    //
    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyOpticalPhotonAnalysis::PostTrackingAction(const G4Track *)
{
    if (!active)
        return;

    //------- add your codes down here
    //
    return;
}

//....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......
void MyOpticalPhotonAnalysis::SteppingAction(const G4Step *aStep)
{
    if (!active)
        return;

    //------- add your codes down here
    //
    G4Track *aTrack = aStep->GetTrack();
    const G4ParticleDefinition *particle = aTrack->GetParticleDefinition();
    G4String ParticleName = particle->GetParticleName();

    if(ParticleName == "opticalphoton")
    {
        G4StepPoint *preStepPoint = aStep->GetPreStepPoint();
        G4StepPoint *postStepPoint = aStep->GetPostStepPoint();
        G4String preVolumeName = preStepPoint->GetTouchableHandle()->GetVolume()->GetName();
        G4String postVolumeName = postStepPoint->GetTouchableHandle()->GetVolume()->GetName();

        G4String proName = postStepPoint->GetProcessDefinedStep()->GetProcessName();

        if((postVolumeName.find(G4String("ChamberPhys")) != G4String::npos) && (preVolumeName.find(G4String("CathodePhys")) != G4String::npos))
        {
            G4ThreeVector postPos = postStepPoint->GetPosition() / mm;
            G4ThreeVector postMomDir = postStepPoint->GetMomentumDirection() / mm;

            fPhotonEnergy[fNumOfOpPhoton] = postStepPoint->GetKineticEnergy() / eV;
            fPhotonCatchTime[fNumOfOpPhoton] = postStepPoint->GetGlobalTime() / ns;
            for(Int_t i = 0; i < 3; ++i)
            {
                fPhotonPos[fNumOfOpPhoton][i] = postPos[i];
                fPhotonMomDir[fNumOfOpPhoton][i] = postMomDir[i];
            }
            aTrack->SetTrackStatus(fStopAndKill);
            ++fNumOfOpPhoton;
        }
    }

    if(fNumOfOpPhoton >= MAXOPPHOTON)
    {
        G4cerr << "In MyOpticalPhotonAnalysis::SteppingAction()" << G4endl;
        G4cerr << "Error!!! Number of OP photon overflow!!!" << G4endl;
        G4cerr << "Please enlarge MAXOPPHOTON" << G4endl;
        exit(0);
    }

    return;
}